<script>
import { BasicMarker } from './js/BasicMarker.js';
import { getMarkerIcon } from './js/icon.js';

function pointOnCubicBezier(cp, t) {
  const cx = 3.0 * (cp[1].lng - cp[0].lng);
  const bx = 3.0 * (cp[2].lng - cp[1].lng) - cx;
  const ax = cp[3].lng - cp[0].lng - cx - bx;

  const cy = 3.0 * (cp[1].lat - cp[0].lat);
  const by = 3.0 * (cp[2].lat - cp[1].lat) - cy;
  const ay = cp[3].lat - cp[0].lat - cy - by;

  const tSquared = t * t;
  const tCubed = tSquared * t;

  const lng = ax * tCubed + bx * tSquared + cx * t + cp[0].lng;
  const lat = ay * tCubed + by * tSquared + cy * t + cp[0].lat;

  return new AMap.LngLat(lng, lat);
}

function computeBezier(points, numberOfPoints) {
  const curve = [];
  const dt = 1.0 / (numberOfPoints - 1);
  for (let i = 0; i < numberOfPoints; i++) {
    curve[i] = pointOnCubicBezier(points, i * dt);
  }
  return curve;
}

function getEllipseHeight(count, maxHeight, minHeight) {
  const height = [];
  const radionUnit = Math.PI / 180;

  for (let i = 0; i < count; i++) {
    const radion = i * radionUnit;
    height.push(minHeight + Math.sin(radion) * maxHeight);
  }

  return height;
}

class Marker extends BasicMarker {
  constructor({ map, data }) {
    super({ map, data });
    super.create();
  }
  getPosition(data = {}) {
    return data.lnglat;
  }
  getIcon() {
    return this.data.icon;
  }
}

export default {
  name: 'map-line',
  render() {
    return null;
  },
  props: {
    map: { default: undefined },
    data: { type: Object, default: () => ({}) },
    option: { type: Object, default: () => ({}) },
  },
  watch: {
    data: {
      immediate: true,
      deep: true,
      handler() {
        this.init();
      },
    },
  },
  methods: {
    init() {
      if (!this.data || !this.data.markerType) {
        return;
      }
      const path = this.getPath();
      if (path.length === 1) {
        this.createNormalMarker(path[0]);
        return;
      }
      this.addExtraPoint(path);
      this.createLine(path);
      this.createStartMarker(path);
      this.createEndMarker(path);
      this.map.setFitView();
    },
    getPoints() {
      return this.data.markerType === 'ybq'
        ? [
            { longitude: this.data.longitude, latitude: this.data.latitude },
            {
              longitude: this.data.new_longitude,
              latitude: this.data.new_latitude,
            },
          ]
        : [
            {
              longitude: this.data.longitude,
              latitude: this.data.latitude,
            },
          ];
    },
    getPath() {
      const points = this.getPoints();
      return points.map((item) => {
        return new AMap.LngLat(item.longitude, item.latitude);
      });
    },
    addExtraPoint(path) {
      function getOffset(list = [], getter = (i) => i) {
        return (getter(list[1]) - getter(list[0])) / 3;
      }
      const offsetX = getOffset(path, (item) => item.lng);
      const offsetY = getOffset(path, (item) => item.lat);
      path.splice(1, 0, {
        lng: path[0].lng + offsetX,
        lat: path[0].lat + offsetY,
      });
      path.splice(2, 0, {
        lng: path[1].lng + offsetX,
        lat: path[1].lat + offsetY,
      });
    },
    createLine(path) {
      const startP = path[0];
      const endP = path[path.length - 1];
      const distance = AMap.GeometryUtil.distance(startP, endP);
      const option = Object.assign(
        {
          numberOfPoints: 200,
          maxHeight: distance * 2,
          minHeight: distance / 1.5,
          width: 2,
          color: 'rgba(55,129,240, 0.9)',
        },
        this.option
      );
      const object3Dlayer = new AMap.Object3DLayer();
      this.meshLine = new AMap.Object3D.MeshLine({
        path: computeBezier(path, option.numberOfPoints, option.minHeight),
        color: option.color,
        width: option.width,
        height: getEllipseHeight(option.numberOfPoints, option.maxHeight, option.minHeight),
      });
      this.meshLine.transparent = true;
      this.meshLine['backOrFront'] = 'both';
      object3Dlayer.add(this.meshLine);
      this.map.add(object3Dlayer);
    },
    createStartMarker(path) {
      const startP = path[0];
      const startMarker = new Marker({
        map: this.map,
        data: {
          lnglat: startP,
          label: '拆迁地',
          icon: getMarkerIcon('./assets/marker/map_bt_cqf.png'),
        },
      });
      startMarker.show();
    },
    createEndMarker(path) {
      const endP = path[path.length - 1];
      const endMarker = new Marker({
        map: this.map,
        data: {
          lnglat: endP,
          label: '安置地',
          icon: getMarkerIcon('./assets/marker/map_bt_ybq.png'),
        },
      });
      endMarker.show();
    },
    createNormalMarker(point) {
      const normalMarker = new Marker({
        map: this.map,
        data: {
          lnglat: point,
          icon: getMarkerIcon(this.data.markerType),
        },
      });
      normalMarker.show();
    },
  },
};
</script>

<style scoped></style>
